/**
 *                     Remixvym (version 0.8.4)
 *             Copyright (c) 2010 by RemixLab, DISI-UNAL
 *            http://www.disi.unal.edu.co/grupos/remixlab/
 *
 * This Java package provides classes to visualize Mind Maps created in VYM
 * (View Your Mind) in a Processing Sketch
 *
 * @author Alvaro Lopez, Juan Baquero
 *
 * This source file is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License as published by the Free
 * Software Foundation; either version 3 of the License, or (at your option)
 * any later version.
 *
 * This code is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
 * more details.
 *
 * A copy of the GNU General Public License is available on the World Wide Web
 * at <http://www.gnu.org/copyleft/gpl.html>. You can also obtain it by
 * writing to the Free Software Foundation, 51 Franklin Street, Fifth Floor
 * Boston, MA 02110, USA
 */
package remixlab.remixvym.core.util.selected;

import java.util.ArrayList;

import processing.core.PFont;
import remixlab.remixvym.MindMap;
import remixlab.remixvym.core.graphics.StyleGraph;
import remixlab.remixvym.core.graphics.node.NodeConstans;
import remixlab.remixvym.core.graphics.text.TextUtil;
import remixlab.remixvym.core.mindmap.Node;


public class TriangleSelectedUtil implements SelectedUtil,NodeConstans{
	

	public void up(Node node, MindMap map, StyleGraph style) {
		
		int i;
		if(!node.selected)
		{
			//CALCULA EL ANCHO DEL NODO, PRIMERO POR EL ANCHO DEL TEXTO
			//LUEGO POR EL NUMERO DE EMOTICONES CON SUS ESPACIOS ENTRE SI
			//Y POR ULTIMO EL ESPACIO PARA ICONOS
			
			PFont font;
			int heigth;
			int defHeigth;
			int sizeDown;
			
			
			if(node.getFather()==null){
				sizeDown = (int)style.sizeFontRoot;
				font = style.fontRootSelected;
				heigth = (int)style.heigthRoot;
				defHeigth = (int)style.defHeigthRoot;
			}
			else if(node.getFather().getFather()==null){
				sizeDown = (int)style.sizeFontChild;
				font = style.fontChildSelected;
				heigth = (int)style.heigthChild;
				defHeigth = (int)style.defHeigthChild;
			}
			else{ 
				sizeDown = (int)style.sizeFontNormal;
				font = style.fontSelected;
				heigth = (int)style.heigthNormal;
				defHeigth = (int)style.defHeigthNormal;
			}
			
			int heigthNode = (int)((heigth*font.getFont().getSize())/sizeDown);
			
			int initSpace = (int)((heigthNode*defInitSpace)/defHeigth);
			int spaceObjects = (int)((heigthNode*defSpaceObjects)/defHeigth);
			int longEmoticon = (int)((heigthNode*defLongEmoticon)/defHeigth);
			int spaceIcons = (int)((heigthNode*defSpaceIcons)/defHeigth);
			
			if(longEmoticon>defLongEmoticon) longEmoticon=defLongEmoticon;
			if(spaceObjects>defSpaceObjects) spaceObjects=defSpaceObjects;
			if(initSpace>defInitSpace) initSpace=defInitSpace;
			
			//LISTA QUE GUARDA EL TEXTO PARA LOS NODOS MULTI-LINEA
			
			ArrayList<String> list = TextUtil.getSize(style,font, node.getInfo());
			
			int wdText = Integer.parseInt(list.get(list.size()-1));
			
			int widthNode = initSpace+wdText;
			
			for(i=0;node.emoticones!=null && i<node.emoticones.size();i++)
				widthNode = widthNode+longEmoticon+spaceObjects;

			widthNode = widthNode+initSpace+spaceIcons;
			
			heigthNode = (heigthNode*(list.size()-1));

			
			incrX = (int)((widthNode-node.width)/2);
			incrY = (int)((heigthNode-node.height)/2);
			
			if(widthNode<node.width)
				incrX=-incrX;
			
//			if(Math.abs(incrX)<(heigth*def10Space)/defHeigth)
//				incrX=(heigth*def10Space)/defHeigth;
			

			hX1 = node.x1 - incrX;
			hY1 = node.y1 - incrY;
			hY2 = node.y2 + incrY;
			hX2 = node.x2 + incrX;

			selected = node;
			cx = node.x1 + (node.width/2);
			cy = node.y1 + (node.height/2);
			width = map.getWidth();
			height = map.getHeight();
			
			calculateRegions();
			
			searchUp(map.getMap());
			

			node.x1 = (int)hX1;
			node.y1 = (int)hY1;
			node.y2 = (int)hY2;
			node.x2 = (int)hX2;
			node.calculate();
			node.selected=true;
		}

	}

	public void down(Node node,MindMap map)
	{
		if(incrX==0 && incrY==0)return;
		
		if(node!=null && node.selected)
		{
			hX1 = node.x1;
			hY1 = node.y1;
			hY2 = node.y2;
			hX2 = node.x2;
			
			node.x1 = node.x1 + incrX;
			node.y1 = node.y1 + incrY;
			node.y2 = node.y2 - incrY;
			node.x2 = node.x2 - incrX;
			node.calculate();

			selected = node;
			
			cx = node.x1 + (node.width/2);
			cy = node.y1 + (node.height/2);
			width = map.getWidth();
			height = map.getHeight();
			
			//calculateRegions();
			
			searchDown(map.getMap());
			
			node.selected = false;
			
			incrX=0;
			incrY=0;
		}
	
	}
	
	//-------------   Movimiento de Nodos ------------------
	
	private void searchUp(Node node) {
		
		if(node!=selected)
		{
			int cox = (int)(node.x1 + (node.width/2));   //Centro en X del nodo a mover
			int coy = (int)(node.y1 + (node.height/2));  //Centro en Y del nodo a mover
			
			int incX =0; //Empuje al nodo a mover en X;
			int incY =0; //Empuje al nodo a mover en Y;
			 
			int yMa =0;  //Valor en Y de la Diagonal mayor;
			int yMe =0;  //Valor en Y de la Diagonal menor;
			
			int xMa =0;  //Valor en X de la Diagonal mayor;
			int xMe =0;  //Valor en X de la Diagonal menor;
			
			//MOVIMIENTO EN X
			
			//X = ( Y - B) / M
			
			
			
			if(cox>cx)
			{
				if(coy>hY2)
				{
					//REGION 3
					
					xMe = (int)((coy - B[2])/M[2]);
					if(cox>xMe)
					{
						xMa = (int)((coy - hB[2])/hM[2]);
						incX=xMa - xMe;
					}
					
				}else if(coy>hY1)
				{
					if(cox>selected.x2)
						incX = (int)incrX+2;
				}else
				{
					// REGION 8
					xMe = (int)((coy - B[7])/M[7]);
					if(cox>xMe)
					{
						xMa = (int)((coy - hB[7])/hM[7]);
						incX=xMa - xMe;
					}
				}
			}
			else
			{
				if(coy>hY2)
				{
					//REGION 4
					xMe = (int)((coy - B[3])/M[3]);
					if(cox<xMe)
					{
						xMa = (int)((coy - hB[3])/hM[3]);
						incX=xMa - xMe;
					}
					
				}else if(coy>hY1)
				{
					if(cox<selected.x1)
						incX = -((int)incrX+2);
				}else
				{
					//REGION 7
					xMe = (int)((coy - B[6])/M[6]);
					if(cox<xMe)
					{
						xMa = (int)((coy - hB[6])/hM[6]);
						incX=xMa - xMe;
					}
				}
			}
			

			node.x1 = node.x1+incX;
			node.x2 = node.x2+incX;

			
			cox = (int)(node.x1 + (node.width/2));   //Centro en X del nodo a mover
			coy = (int)(node.y1 + (node.height/2));  //Centro en Y del nodo a mover
			
			
			//MOVIMIENTO EN Y
			
			// Y=MX+B
			
			
			if(coy<cy)
			{
				if(cox>hX2)
				{
					//REGION 1
					
					yMe = (int)(M[0]*cox + B[0]);
					if(coy<yMe)
					{
						yMa = (int)(hM[0]*cox + hB[0]);
						incY=yMa - yMe;
					}
					
				}
				else if(cox>hX1)
				{
					if(coy<selected.y1)
						incY= -((int)incrY+2);
				}
				else
				{
					// REGION 6
					
					yMe = (int)(M[5]*cox + B[5]);
					if(coy<yMe)
					{
						yMa = (int)(hM[5]*cox + hB[5]);
						incY=yMa - yMe;
					}
					
				}
				
			}else
			{
				if(cox>hX2)
				{
					// REGION 2
					
					yMe = (int)(M[1]*cox + B[1]);
					if(coy>yMe)
					{
						yMa = (int)(hM[1]*cox + hB[1]);
						incY=yMa - yMe;
					}
					
					
				}
				else if(cox>hX1)
				{
					if(coy>selected.y2)
						incY= (int)incrY+2;
				}
				else
				{
					//REGION 5
					
					yMe = (int)(M[4]*cox + B[4]);
					if(coy>yMe)
					{
						yMa = (int)(hM[4]*cox + hB[4]);
						incY=yMa - yMe;
					}
					
				}
				
				
			}
			
			node.y1 = node.y1+incY;
			node.y2 = node.y2+incY;

		}

		for(int i=0 ; i<node.children.size();i++)
		{
				searchUp(node.children.get(i));
		}
	}
	
	private void searchDown(Node node) {
		
		if(node!=selected)
		{
			int cox = (int)(node.x1 + (node.width/2));   //Centro en X del nodo a mover
			int coy = (int)(node.y1 + (node.height/2));  //Centro en Y del nodo a mover
			
			int incX =0; //Empuje al nodo a mover en X;
			int incY =0; //Enpuje al nodo a mover en Y;
			 
			int yMa =0;  //Valor en Y de la Diagonal mayor;
			int yMe =0;  //Valor en Y de la Diagonal menor;
			
			int xMa =0;  //Valor en X de la Diagonal mayor;
			int xMe =0;  //Valor en X de la Diagonal menor;			
			
			//MOVIMIENTO EN Y
			
			// Y=MX+B
			
			
			if(coy<cy)
			{
				if(cox>hX2)
				{
					//REGION 1
					
					yMe = (int)(M[0]*cox + B[0]);
					if(coy<yMe)
					{
						yMa = (int)(hM[0]*cox + hB[0]);
						incY=yMa - yMe;
					}
					
				}
				else if(cox>hX1)
				{
					if(coy<selected.y1)
						incY= -((int)incrY+2);
				}
				else
				{
					// REGION 6
					
					yMe = (int)(M[5]*cox + B[5]);
					if(coy<yMe)
					{
						yMa = (int)(hM[5]*cox + hB[5]);
						incY=yMa - yMe;
					}
					
				}
				
			}else
			{
				if(cox>hX2)
				{
					// REGION 2
					
					yMe = (int)(M[1]*cox + B[1]);
					if(coy>yMe)
					{
						yMa = (int)(hM[1]*cox + hB[1]);
						incY=yMa - yMe;
					}
					
					
				}
				else if(cox>hX1)
				{
					if(coy>selected.y2)
						incY= (int)incrY+2;
				}
				else
				{
					//REGION 5
					
					yMe = (int)(M[4]*cox + B[4]);
					if(coy>yMe)
					{
						yMa = (int)(hM[4]*cox + hB[4]);
						incY=yMa - yMe;
					}
				}
			}

			node.y1 = node.y1-incY;
			node.y2 = node.y2-incY;
			
			cox = (int)(node.x1 + (node.width/2));   //Centro en X del nodo a mover
			coy = (int)(node.y1 + (node.height/2));  //Centro en Y del nodo a mover
			
			//MOVIMIENTO EN X
			
			//X = ( Y - B) / M
			
			if(cox>cx)
			{
				if(coy>hY2)
				{
					//REGION 3
					
					xMe = (int)((coy - B[2])/M[2]);
					if(cox>xMe)
					{
						xMa = (int)((coy - hB[2])/hM[2]);
						incX=xMa - xMe;
					}
					
				}else if(coy>hY1)
				{
					if(cox>selected.x2)
						incX = (int)incrX+2;
				}else
				{
					// REGION 8
					xMe = (int)((coy - B[7])/M[7]);
					if(cox>xMe)
					{
						xMa = (int)((coy - hB[7])/hM[7]);
						incX=xMa - xMe;
					}
				}
			}
			else
			{
				if(coy>hY2)
				{
					//REGION 4
					xMe = (int)((coy - B[3])/M[3]);
					if(cox<xMe)
					{
						xMa = (int)((coy - hB[3])/hM[3]);
						incX=xMa - xMe;
					}
					
				}else if(coy>hY1)
				{
					if(cox<selected.x1)
						incX = -((int)incrX+2);
				}else
				{
					//REGION 7
					xMe = (int)((coy - B[6])/M[6]);
					if(cox<xMe)
					{
						xMa = (int)((coy - hB[6])/hM[6]);
						incX=xMa - xMe;
					}
				}
			}
			

			node.x1 = node.x1-incX;
			node.x2 = node.x2-incX;
			
		}

		for(int i=0 ; i<node.children.size();i++)
		{
				searchDown(node.children.get(i));
		}
	}
	
	private void calculateRegions()
	{
		//REGION 1
		
		M[0] = (float)(cy - selected.y1)/(float)(width-selected.x2);
		B[0] = (float)(selected.y1*width - selected.x2*cy)/(float)(width-selected.x2);
		
		hM[0] = (float)(cy - hY1)/(float)(width-hX2);
		hB[0] = (float)(hY1*width - hX2*cy)/(float)(width-hX2);
		
		//REGION 2
		
		M[1] = (float)(cy-selected.y2)/(float)(width-selected.x2);
		B[1] = (float)(selected.y2*width - selected.x2*cy)/(float)(width-selected.x2);
		
		hM[1] = (float)(cy - hY2)/(float)(width-hX2);
		hB[1] = (float)(hY2*width - hX2*cy)/(float)(width-hX2);
		
		//REGION 3
		
		M[2] = (float)(selected.y2-height)/(float)(selected.x2-cx);
		B[2] = (float)(selected.x2*height-selected.y2*cx)/(float)(selected.x2-cx);
		
		hM[2] = (float)(hY2-height)/(float)(hX2-cx);
		hB[2] = (float)(hX2*height-hY2*cx)/(float)(hX2-cx);
		
		//REGION 4
		
		M[3] = (float)(height-selected.y2)/(float)(cx-selected.x1);
		B[3] = (float)(selected.y2*cx-selected.x1*height)/(float)(cx-selected.x1);
		
		hM[3] = (float)(height-hY2)/(float)(cx-hX1);
		hB[3] = (float)(hY2*cx-hX1*height)/(float)(cx-hX1);
		
		//REGION 5
		
		M[4] = (float)(selected.y2-cy)/(float)(selected.x1);
		B[4] = cy;
		
		hM[4] = (float)(hY2-cy)/(float)(hX1);
		hB[4] = (float)cy;
		
		//REGION 6
		
		M[5] = (float)(selected.y1 - cy)/(float)(selected.x1);
		B[5] = (float)cy;
		
		hM[5] = (float)(hY1 - cy)/(float)(hX1);
		hB[5] = (float)cy;
		
		//REGION 7
		
		M[6] = -(float)(selected.y1)/(float)(cx-selected.x1);
		B[6] = (float)(selected.y1*cx)/(float)(cx-selected.x1);
		
		hM[6] = -(float)(hY1)/(float)(cx-hX1);
		hB[6] = (float)(hY1*cx)/(float)(cx-hX1);
		
		//REGION 8
		
		M[7] = (float)(selected.y1)/(float)(selected.x2-cx);
		B[7] = -(float)(selected.y1*cx)/(float)(selected.x2-cx);
		
		hM[7] = (float)(hY1)/(float)(hX2-cx);
		hB[7] = -(float)(hY1*cx)/(float)(hX2-cx);

		//verify();
	}
	
//	@SuppressWarnings("unused")
//	private void verify()
//	{
//		for(float i=hX2;i<width;i=i+1)
//			parent.point(i, (hM[0]*i)+hB[0]);
//		
//		for(float i=selected.x2;i<width;i=i+1)
//			parent.point(i, (M[0]*i)+B[0]);
//		
//		for(float i=hX2;i<width;i=i+1)
//			parent.point(i, (hM[1]*i)+hB[1]);
//		
//		for(float i=selected.x2;i<width;i=i+1)
//			parent.point(i, (M[1]*i)+B[1]);
//		
//		for(float i=hY2;i<height;i=i+1)
//			parent.point((i-hB[2])/hM[2], i);
//		
//		for(float i=selected.y2;i<height;i=i+1)
//			parent.point((i-B[2])/M[2], i);
//		
//		for(float i=hY2;i<height;i=i+1)
//			parent.point((i-hB[3])/hM[3], i);
//		
//		for(float i=selected.y2;i<height;i=i+1)
//			parent.point((i-B[3])/M[3], i);
//		
//		for(float i=0;i<hX1;i=i+1)
//			parent.point(i, (hM[4]*i)+hB[4]);
//		
//		for(float i=0;i<selected.x1;i=i+1)
//			parent.point(i, (M[4]*i)+B[4]);
//		
//		for(float i=0;i<hX1;i=i+1)
//			parent.point(i, (hM[5]*i)+hB[5]);
//		
//		for(float i=0;i<selected.x1;i=i+1)
//			parent.point(i, (M[5]*i)+B[5]);
//		
//		for(float i=0;i<hY1;i=i+1)
//			parent.point((i-hB[6])/hM[6], i);
//		
//		for(float i=0;i<selected.y1;i=i+1)
//			parent.point((i-B[6])/M[6], i);
//		
//		for(float i=0;i<hY1;i=i+1)
//			parent.point((i-hB[7])/hM[7], i);
//		
//		for(float i=0;i<selected.y1;i=i+1)
//			parent.point((i-B[7])/M[7], i);
//	}
	
	private int cx;
	private int cy;
	private int width;
	private int height;
	private Node selected;
	
	//COORDENADAS DEL NODO YA AUMENTADO
	
	private int hX1;
	private int hX2;
	private int hY1;
	private int hY2;
	
	private float hM[] = new float[8]; //Pendiente de la recta diagonal aumentada
	private float hB[] = new float[8]; //B de la recta diagonal actual
	private float M[] = new float[8]; //Pendiente de la recta diagonal actual
	private float B[] = new float[8]; //B de la recta diagonal actual
	
	//INCREMENTO DEL NODO
	
	private int incrY;
	private int incrX;
}
